/*
 * Copyright (C) 2018 Ortega Froysa, Nicolás <nortega@themusicinnoise.net>
 * Author: Ortega Froysa, Nicolás <nortega@themusicinnoise.net>
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include "Shader.hpp"
#include "System.hpp"

#include <fstream>
#include <sstream>

Shader::Shader(const std::string &vShaderPath,
		const std::string &fShaderPath)
{
	// Load the code from the files.
	std::string vShaderCode, fShaderCode;
	std::ifstream vShaderFile, fShaderFile;
	vShaderFile.exceptions(std::ifstream::failbit bitor
			std::ifstream::badbit);
	fShaderFile.exceptions(std::ifstream::failbit bitor
			std::ifstream::badbit);
	try
	{
		vShaderFile.open(vShaderPath);
		fShaderFile.open(fShaderPath);
		std::stringstream vShaderStream, fShaderStream;
		vShaderStream << vShaderFile.rdbuf();
		fShaderStream << fShaderFile.rdbuf();
		vShaderFile.close();
		fShaderFile.close();
		vShaderCode = vShaderStream.str();
		fShaderCode = fShaderStream.str();
	}
	catch(const std::exception &e)
	{
		System::logger->writeError(
				std::string("Failed to read from file: ") +
				e.what());
	}

	// Compile the shaders
	unsigned int vertexId, fragmentId;
	int res;
	char infoLog[512];

	vertexId = glCreateShader(GL_VERTEX_SHADER);
	{
		const char *vShaderCodeChar = vShaderCode.c_str();
		glShaderSource(vertexId, 1,
				&vShaderCodeChar, nullptr);
	}
	glCompileShader(vertexId);
	glGetShaderiv(vertexId, GL_COMPILE_STATUS, &res);
	if(not res)
	{
		glGetShaderInfoLog(vertexId, 512, nullptr, infoLog);
		System::logger->writeError(
				std::string(
					"Vertex shader compilation failed: ") +
				infoLog);
	}
	fragmentId = glCreateShader(GL_FRAGMENT_SHADER);
	{
		const char *fShaderCodeChar = fShaderCode.c_str();
		glShaderSource(fragmentId, 1,
				&fShaderCodeChar, nullptr);
	}
	glCompileShader(fragmentId);
	glGetShaderiv(fragmentId, GL_COMPILE_STATUS, &res);
	if(not res)
	{
		glGetShaderInfoLog(fragmentId, 512, nullptr, infoLog);
		System::logger->writeError(
				std::string(
					"Fragment shader compilation failed: ") +
				infoLog);
	}

	// Link the program
	id = glCreateProgram();
	glAttachShader(id, vertexId);
	glAttachShader(id, fragmentId);
	glLinkProgram(id);

	glGetProgramiv(id, GL_LINK_STATUS, &res);
	if(not res)
	{
		glGetProgramInfoLog(id, 512, nullptr, infoLog);
		System::logger->writeError(
				std::string("Failed to link program: ") +
				infoLog);
	}

	// Delete the shaders
	glDeleteShader(vertexId);
	glDeleteShader(fragmentId);
}
